package testes;

import agenda.Contato;
import agenda.Evento;
import agenda.Skype;
import excecoes.DuracaoInvalida;
import excecoes.HorarioInvalido;
import excecoes.DataInvalida;
import org.junit.*;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class EventoTest {

	private final int algumAnoValido = 1994, algumMesValido = 05, algumDiaValido = 11, algumaHoraValida = 13;

	private Evento evento1, evento2;

	@Before
	public void setUp() throws DataInvalida, HorarioInvalido {
		evento1 = new Evento("Testando", "28/10/2011", "10:59", "00:30", "descricao", "tipo");
		evento2 = new Evento("Testando2", "11/06/1994", "04:10", "02:30", "descricao2");
	}

	@Test
	public void testGetNome() {
		Assert.assertEquals("Testando", evento1.getNome());
		Assert.assertEquals("Testando2", evento2.getNome());
	}

	@Test
	public void testGetDataInicioFormatada() {
		Assert.assertEquals("28/10/2011", evento1.getDataInicioFormatada());
		Assert.assertEquals("11/06/1994", evento2.getDataInicioFormatada());
	}

	@Test
	public void testGetHorarioInicioFormatado() {
		Assert.assertEquals("10:59", evento1.getHorarioInicioFormatado());
		Assert.assertEquals("04:10", evento2.getHorarioInicioFormatado());
	}

	@Test
	public void testGetDuracao() {
		Assert.assertEquals("00 horas e 30 minutos", evento1.getDuracao());
		Assert.assertEquals("02 horas e 30 minutos", evento2.getDuracao());
	}

	@Test
	public void testGetDescricao() {
		Assert.assertEquals("descricao", evento1.getDescricao());
		Assert.assertEquals("descricao2", evento2.getDescricao());
	}

	@Test
	public void testGetTipo() {
		Assert.assertEquals("tipo", evento1.getTipo());
		Assert.assertNull(evento2.getTipo());
	}

	@Test
	public void testGetDataTermino() {
		Calendar dt = (GregorianCalendar)evento1.getDataInicio().clone();
		dt.add(Calendar.MINUTE, 30);
		dt.add(Calendar.HOUR_OF_DAY, 00);

		Assert.assertEquals(dt, evento1.getDataTermino());

		dt = (GregorianCalendar)evento2.getDataInicio().clone();
		dt.add(Calendar.MINUTE, 30);
		dt.add(Calendar.HOUR_OF_DAY, 2);

		Assert.assertEquals(dt, evento2.getDataTermino());
	}

	@Test
	public void testValidaHorarioEValidaDuracao() {

		try {
			evento1.validaHorario("", "Horario invalido!");
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Horario invalido!", h.getMessage());
		}

		try {
			evento1.validaHorario("abc", "Duracao invalida!");
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Duracao invalida!", h.getMessage());
		}

		try {
			evento1.validaHorario("10h03min", "Horario invalido!");
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Horario invalido!", h.getMessage());
		}

		try {
			evento1.validaHorario("17 : 15", "Duracao invalida!");
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Duracao invalida!", h.getMessage());
		}

		try {
			evento1.validaHorario("hh:mm", "Horario invalido!");
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Horario invalido!", h.getMessage());
		}

		try {
			evento1.validaHorario("10:15", "Horario invalido!");
			evento1.validaHorario("00:00", "Duracao invalida!");
			evento1.validaHorario("23:59", "Horario invalido!");

			//Os metodos validaHora(s) e validaMinuto(s) sao responsaveis por verificar a validade de horas e
			//minutos, respectivamente. Isso nao cabe ao validaHorario()

			evento1.validaHorario("99:99", "Horario invalido!");

		} catch(HorarioInvalido h) {
			Assert.fail("Os horarios/duracoes sao validos. Nao devo chegar aqui.");
		}

	}

	@Test
	public void testValidaHoras() {
		try {
			evento1.validaHoras(-1);
		} catch (DuracaoInvalida d) {
			Assert.assertEquals("Quantidade de horas invalida!", d.getMessage());
		}

		try {
			evento1.validaHoras(123);
			evento1.validaHoras(1);
			evento1.validaHoras(0);
		} catch (DuracaoInvalida d) {
			Assert.fail("As quantidades de horas sao validas. Nao devo chegar aqui.");
		}
	}

	@Test
	public void testValidaMinutos() {

		try {
			evento1.validaMinutos(1, -1);
		} catch (DuracaoInvalida d) {
			Assert.assertEquals("Quantidade de minutos invalida!", d.getMessage());
		}

		try {
			evento1.validaMinutos(1, 60);
		} catch (DuracaoInvalida d) {
			Assert.assertEquals("Quantidade de minutos invalida!", d.getMessage());
		}

		try {
			evento1.validaMinutos(0, 0);
		} catch (DuracaoInvalida d) {
			Assert.assertEquals("Quantidade de minutos invalida!", d.getMessage());
		}

		try {
			evento1.validaMinutos(5, 3);
			evento1.validaMinutos(12, 59);
			evento1.validaMinutos(01, 05);
		} catch (DuracaoInvalida d) {
			Assert.fail("As quantidade de minutos sao validas. Nao devo chegar aqui.");
		}

	}

	@Test
	public void testValidaData() {

		try {
			Evento.validaData("");
		} catch (DataInvalida d) {
			Assert.assertEquals("Data invalida! Use o formato dd/MM/aaaa", d.getMessage());
		}

		try {
			Evento.validaData("!@/#$/%�&*");
		} catch (DataInvalida d) {
			Assert.assertEquals("Data invalida! Use o formato dd/MM/aaaa", d.getMessage());
		}

		try {
			Evento.validaData("11-05-1994");
		} catch (DataInvalida d) {
			Assert.assertEquals("Data invalida! Use o formato dd/MM/aaaa", d.getMessage());
		}

		try {
			Evento.validaData("0123456789");
		} catch (DataInvalida d) {
			Assert.assertEquals("Data invalida! Use o formato dd/MM/aaaa", d.getMessage());
		}

		try {
			Evento.validaData("dd/05/2011");
		} catch (DataInvalida d) {
			Assert.assertEquals("Data invalida! Use o formato dd/MM/aaaa", d.getMessage());
		}

		try {
			Evento.validaData("ab/cd/efgh");
		} catch (DataInvalida d) {
			Assert.assertEquals("Data invalida! Use o formato dd/MM/aaaa", d.getMessage());
		}

		try {
			Evento.validaData("11/5/2010");
		} catch (DataInvalida d) {
			Assert.assertEquals("Data invalida! Use o formato dd/MM/aaaa", d.getMessage());
		}

		try {
			Evento.validaData("11/05/94");
		} catch (DataInvalida d) {
			Assert.assertEquals("Data invalida! Use o formato dd/MM/aaaa", d.getMessage());
		}

		try {
			Evento.validaData("11/05/1994");
			Evento.validaData("00/00/0000");
			Evento.validaData("99/99/9999");
		} catch (DataInvalida d) {
			Assert.fail("As datas sao validas. Nao devo chegar aqui.");
		}

	}

	@Test
	public void testValidaAno() {

		try {
			Evento.validaAno(new GregorianCalendar(), -1);
		} catch (DataInvalida d) {
			Assert.assertEquals("Ano invalido!", d.getMessage());
		}

		try {
			Evento.validaAno(new GregorianCalendar(), 0);
		} catch (DataInvalida d) {
			Assert.assertEquals("Ano invalido!", d.getMessage());
		}

		try {
			Evento.validaAno(new GregorianCalendar(), 1);
			Evento.validaAno(new GregorianCalendar(), 2011);
			Evento.validaAno(new GregorianCalendar(), 99999999);
		} catch (DataInvalida d) {
			Assert.fail("Os anos sao validos. Nao devo chegar aqui.");
		}

	}

	@Test
	public void testValidaMes() {

		Calendar data = new GregorianCalendar();
		data.set(Calendar.YEAR, algumAnoValido);

		try {
			Evento.validaMes(data, -1);
		} catch (DataInvalida d) {
			Assert.assertEquals("Mes invalido!", d.getMessage());
		}

		try {
			Evento.validaMes(data, 12);
		} catch (DataInvalida d) {
			Assert.assertEquals("Mes invalido!", d.getMessage());
		}

		try {
			Evento.validaMes(data, 123);
		} catch (DataInvalida d) {
			Assert.assertEquals("Mes invalido!", d.getMessage());
		}

		try {
			Evento.validaMes(data, 05);
			Evento.validaMes(data, 00);
			Evento.validaMes(data, 11);

		} catch (DataInvalida d) {
			Assert.fail("Os meses sao validos. Nao devo chegar aqui.");
		}

	}

	@Test
	public void testValidaDia() {

		Calendar data = new GregorianCalendar();
		data.set(Calendar.YEAR, algumAnoValido);
		data.set(Calendar.MONTH, algumMesValido);

		try {
			Evento.validaDia(data, 32);
		} catch (DataInvalida d) {
			Assert.assertEquals("Dia invalido!", d.getMessage());
		}

		try {
			Evento.validaDia(data, 00);
		} catch (DataInvalida d) {
			Assert.assertEquals("Dia invalido!", d.getMessage());
		}

		try {
			data.set(Calendar.MONTH, 03); // um mes de 30 dias
			Evento.validaDia(data, 31);
		} catch (DataInvalida d) {
			Assert.assertEquals("Dia invalido!", d.getMessage());
		}

		try {
			data.set(Calendar.MONTH, 01); // fevereiro
			Evento.validaDia(data, 30);
		} catch (DataInvalida d) {
			Assert.assertEquals("Dia invalido!", d.getMessage());
		}

		try {
			data.set(Calendar.YEAR, 2011); // um ano que nao e bissexto
			Evento.validaDia(data, 29);
		} catch (DataInvalida d) {
			Assert.assertEquals("Dia invalido!", d.getMessage());
		}

		try {
			data.set(Calendar.YEAR, algumAnoValido);
			data.set(Calendar.MONTH, algumMesValido);

			Evento.validaDia(data, 30);
			Evento.validaDia(data, 1);
			Evento.validaDia(data, 15);

			data.set(Calendar.MONTH, 00); // um mes com 31 dias
			Evento.validaDia(data, 31);

			data.set(Calendar.YEAR, 2012); // um ano bissexto
			data.set(Calendar.MONTH, 01); // fevereiro
			Evento.validaDia(data, 28);
			Evento.validaDia(data, 29);

		} catch (DataInvalida d) {
			Assert.fail("Os dias sao validos. Nao devo chegar aqui.");
		}
	}

	@Test
	public void testValidaHora() {

		evento1.getDataInicio().set(Calendar.YEAR, algumAnoValido);
		evento1.getDataInicio().set(Calendar.MONTH, algumMesValido);
		evento1.getDataInicio().set(Calendar.DAY_OF_MONTH, algumDiaValido);

		try {
			evento1.validaHora(24);
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Hora invalida!", h.getMessage());
		}

		try {
			evento1.validaHora(-1);
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Hora invalida!", h.getMessage());
		}

		try {
			evento1.validaHora(123);
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Hora invalida!", h.getMessage());
		}

		try {
			evento1.validaHora(23);
			evento1.validaHora(00);
			evento1.validaHora(12);
		} catch (HorarioInvalido h) {
			Assert.fail("As horas sao validas. Nao devo chegar aqui.");
		}

	}

	@Test
	public void testValidaMinuto() {

		evento1.getDataInicio().set(Calendar.YEAR, algumAnoValido);
		evento1.getDataInicio().set(Calendar.MONTH, algumMesValido);
		evento1.getDataInicio().set(Calendar.DAY_OF_MONTH, algumDiaValido);
		evento1.getDataInicio().set(Calendar.HOUR_OF_DAY, algumaHoraValida);

		try {
			evento1.validaMinuto(-1);
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Minuto invalido!", h.getMessage());
		}

		try {
			evento1.validaMinuto(60);
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Minuto invalido!", h.getMessage());
		}

		try {
			evento1.validaMinuto(-1);
		} catch (HorarioInvalido h) {
			Assert.assertEquals("Minuto invalido!", h.getMessage());
		}

		try {
			evento1.validaMinuto(59);
			evento1.validaMinuto(0);
		} catch (HorarioInvalido h) {
			Assert.fail("Os minutos sao validos. Nao devo chegar aqui.");
		}

	}

	@Test
	public void testSetDescricao() {
		Assert.assertNotSame("ois", evento1.getDescricao());
		evento1.setDescricao("ois");
		Assert.assertEquals("ois", evento1.getDescricao());
	}

	@Test
	public void testSetNome() {
		Assert.assertNotSame("bobs", evento1.getNome());
		evento1.setNome("bobs");
		Assert.assertEquals("bobs", evento1.getNome());
	}

	@Test
	public void testSetTipo() {
		Assert.assertNotSame("bla", evento1.getTipo());
		evento1.setTipo("bla");
		Assert.assertEquals("bla", evento1.getTipo());
	}

	@Test
	public void testSetDuracao() throws HorarioInvalido {
		Assert.assertNotSame("15 horas e 15 minutos", evento1.getDuracao());
		evento1.setDuracao("02:29");
		Assert.assertEquals("02 horas e 29 minutos", evento1.getDuracao());
	}

	@Test
	public void testSetDataTermino() throws HorarioInvalido {
		evento2.setDataTermino("10:30");
		Assert.assertEquals(14, evento2.getDataTermino().get(Calendar.HOUR_OF_DAY));
		Assert.assertEquals(40, evento2.getDataTermino().get(Calendar.MINUTE));
	}

	@Test
	public void testSetHorarioInicio() {
		Assert.assertNotSame(05, evento2.getDataInicio().get(Calendar.HOUR_OF_DAY));
		Assert.assertNotSame(30, evento2.getDataInicio().get(Calendar.MINUTE));

		try {
			evento2.setHorarioInicio("05:30");
		} catch(HorarioInvalido h) {
			Assert.fail();
		}

		Assert.assertEquals(05, evento2.getDataInicio().get(Calendar.HOUR_OF_DAY));
		Assert.assertEquals(30, evento2.getDataInicio().get(Calendar.MINUTE));

		Assert.assertEquals("05:30", evento2.getHorarioInicioFormatado());

	}

	@Test
	public void testSetDataInicio() {
		Assert.assertNotSame(1990, evento1.getDataInicio().get(Calendar.YEAR));
		Assert.assertNotSame(04, evento1.getDataInicio().get(Calendar.MONTH));
		Assert.assertNotSame(13, evento1.getDataInicio().get(Calendar.DAY_OF_MONTH));

		try {
			evento1.setDataInicio("13/05/1990");
		} catch(DataInvalida d) {
			Assert.fail();
		}

		Assert.assertEquals(1990, evento1.getDataInicio().get(Calendar.YEAR));
		Assert.assertEquals(04, evento1.getDataInicio().get(Calendar.MONTH));
		Assert.assertEquals(13, evento1.getDataInicio().get(Calendar.DAY_OF_MONTH));

		Assert.assertEquals("13/05/1990", evento1.getDataInicioFormatada());
	}

	@Test
	public void testCompareTo() {

		Assert.assertTrue(evento2.compareTo(evento1) < 0);
		Assert.assertTrue(evento1.compareTo(evento2) > 0);

		try {
			evento2.setDataInicio("28/10/2011");
			evento2.setHorarioInicio("10:59");

			Assert.assertTrue(evento1.compareTo(evento2) == 0);

			evento2.setHorarioInicio("10:58");
			Assert.assertTrue(evento2.compareTo(evento1) < 0);
			Assert.assertTrue(evento1.compareTo(evento2) > 0);

			evento2.setHorarioInicio("11:00");
			Assert.assertTrue(evento2.compareTo(evento1) > 0);
			Assert.assertTrue(evento1.compareTo(evento2) < 0);

		} catch (Exception e) {
			Assert.fail();
		}
	}

	@Test
	public void testAddParticipantes() {

		try {
			Contato c1 = new Contato("Dug", "casa dele", "10/10", new Skype("dug"));
			Contato c2 = new Contato("Bobs", "casa dele", "10/10", new Skype("bobs"));
			Contato c3 = new Contato("Calvin", "casa dele", "10/10", new Skype("ginzo"));

			Assert.assertTrue(evento1.getParticipantes().isEmpty());

			evento1.addParticipante(c1);
			Assert.assertEquals(1, evento1.getParticipantes().size());
			Assert.assertEquals("Dug", evento1.getParticipantes().get(0).getNome());

			evento1.addParticipante(c2);
			Assert.assertEquals(2, evento1.getParticipantes().size());
			Assert.assertEquals("Bobs", evento1.getParticipantes().get(0).getNome());
			Assert.assertEquals("Dug", evento1.getParticipantes().get(1).getNome());

			evento1.addParticipante(c3);
			Assert.assertEquals(3, evento1.getParticipantes().size());
			Assert.assertEquals("Bobs", evento1.getParticipantes().get(0).getNome());
			Assert.assertEquals("Calvin", evento1.getParticipantes().get(1).getNome());
			Assert.assertEquals("Dug", evento1.getParticipantes().get(2).getNome());

		} catch (Exception e) {
			Assert.fail();
		}
	}

	@Test
	public void testIntersecta() {

		try {
			Assert.assertFalse(evento1.intersecta(evento2));

			evento1.setDataInicio("10/10/2010");
			evento2.setDataInicio("10/10/2010");

			evento1.setHorarioInicio("04:30");
			evento2.setHorarioInicio("04:20");

			evento1.setDuracao("00:10");
			evento2.setDuracao("00:15");

			Assert.assertTrue(evento1.intersecta(evento2));

			evento2.setDuracao("00:10");
			Assert.assertFalse(evento1.intersecta(evento2));

			evento2.setHorarioInicio("04:30");
			evento1.setDuracao("00:02");

		} catch (Exception e) {
			Assert.fail();
		}
	}

	@Test
	public void testToString() {

		Assert.assertEquals(
		"Evento Testando" +
		"\nData de inicio: 28/10/2011" +
		"\nHorario de inicio: 10:59" +
		"\nDuracao: 00 horas e 30 minutos" +
		"\nDescricao: descricao" +
		"\nTipo: tipo" +
		"\n" +
		"\nNao ha contatos cadastrados neste evento."
		, evento1.toString());

		try {
			evento1.addParticipante(new Contato("Dug", "casa dele", "11/05", new Skype("dug")));
			evento1.addParticipante(new Contato("Bobs", "casa dele", "11/05", new Skype("bobs")));
		} catch (Exception blabla) {
			Assert.fail();
		}

		Assert.assertEquals(
				"Evento Testando" +
				"\nData de inicio: 28/10/2011" +
				"\nHorario de inicio: 10:59" +
				"\nDuracao: 00 horas e 30 minutos" +
				"\nDescricao: descricao" +
				"\nTipo: tipo" +
				"\n" +
				"\nContatos cadastrados neste evento:" +
				"\nBobs" +
				"\nDug"
				, evento1.toString());
	}
}